/**********************************************
*  Classes:   CameraMover
*  Desc:      Derives from EventListener. When a
*             camera move event has been issued
*             the camera mover moves the camera :P
*  Author:    Vaios Kalpias-Ilias (C) 2008-2009
***********************************************/

#include "CameraMover.h"
#include "InputManager.h"
#include "CdnRenderer.h"
#include "EventManager.h"
#include "Callback.h"

//----------------------------------------------------
/**
* Ctor
* 
**/
CameraMover::CameraMover() 
: m_spCamera(),
  m_pRenderer(0),
  m_pEventMgr(0),
  m_pInputMgr(0),
  m_kfMoveSpeed(1.0f)
{
	
}
//----------------------------------------------------
/**
* Dtor
* 
**/
CameraMover::~CameraMover()
{
	m_spCamera = CameraPtr();
}
//----------------------------------------------------
/**
* Registers listener with the EventManager and lets the
* InputManager know to create an event when
* the keys to move the camera are pressed
* 
**/
bool CameraMover::Init()
{
	SetInterested();

	m_pRenderer = CdnRenderer::GetInstance();
	if (!m_pRenderer) return false;

	m_pEventMgr = EventManager::GetInstance();
	if (!m_pEventMgr) return false;

	m_pInputMgr = InputManager::GetInstance();
	if (!m_pInputMgr) return false;

	m_pEventMgr->Register(this);
	m_pInputMgr->AssignFuncKeyDown
		(0x57, BindFunc(CameraMover, CreateMoveUpEvent, this));
	m_pInputMgr->AssignFuncKeyDown
		(0x53, BindFunc(CameraMover, CreateMoveDownEvent, this));
	m_pInputMgr->AssignFuncKeyDown
		(0x44, BindFunc(CameraMover, CreateMoveRightEvent, this));
	m_pInputMgr->AssignFuncKeyDown
		(0x41, BindFunc(CameraMover, CreateMoveLeftEvent, this));
	m_pInputMgr->AssignFuncKeyDown
		(0x51, BindFunc(CameraMover, CreateMoveForwardEvent, this));
	m_pInputMgr->AssignFuncKeyDown
		(0x45, BindFunc(CameraMover, CreateMoveBackEvent, this));

	return true;
}
//----------------------------------------------------
/**
*  makes the listener interested in a number of events
* 
**/
void CameraMover::SetInterested()
{
	m_interestedEvents.insert(std::make_pair(Event::EVENT_MOVE_CAMERA_UP, (Event*)0));
	m_interestedEvents.insert(std::make_pair(Event::EVENT_MOVE_CAMERA_DOWN, (Event*)0));
	m_interestedEvents.insert(std::make_pair(Event::EVENT_MOVE_CAMERA_LEFT, (Event*)0));
	m_interestedEvents.insert(std::make_pair(Event::EVENT_MOVE_CAMERA_RIGHT, (Event*)0));
	m_interestedEvents.insert(std::make_pair(Event::EVENT_MOVE_CAMERA_FORWARD, (Event*)0));
	m_interestedEvents.insert(std::make_pair(Event::EVENT_MOVE_CAMERA_BACK, (Event*)0));
}

//----------------------------------------------------
/**
*  Handles move event
* 
**/
void CameraMover::HandleEvent(const Event& e)
{
	switch(e.GetCode())
	{
	case Event::EVENT_MOVE_CAMERA_UP:
		MoveCameraUp();
		break;
	case Event::EVENT_MOVE_CAMERA_DOWN:
		MoveCameraDown();
		break;
	case Event::EVENT_MOVE_CAMERA_LEFT:
		MoveCameraLeft();
		break;
	case Event::EVENT_MOVE_CAMERA_RIGHT:
		MoveCameraRight();
		break;
	case Event::EVENT_MOVE_CAMERA_FORWARD:
		MoveCameraForward();
		break;
	case Event::EVENT_MOVE_CAMERA_BACK:
		MoveCameraBack();
		break;
	default:
		return;
	}
}

//----------------------------------------------------
/**
*  Moves camera up
* 
**/
void CameraMover::MoveCameraUp()
{
	m_spCamera = m_pRenderer->GetCamera();

	if (m_spCamera)
	{
		const mth::Vector3& kUp = m_spCamera->GetGlobalUp();//m_spCamera->GetGlobalRotation().GetColumn(1);
		const mth::Vector3& kPos = m_spCamera->GetTranslation();

		m_spCamera->SetTranslation(kPos + kUp*m_kfMoveSpeed);
	}
}


//----------------------------------------------------
/**
*  Moves camera down
* 
**/
void CameraMover::MoveCameraDown()
{
	m_spCamera = m_pRenderer->GetCamera();

	if (m_spCamera)
	{
		const mth::Vector3& kDown = -m_spCamera->GetGlobalUp();//m_spCamera->GetGlobalRotation().GetColumn(1);
		const mth::Vector3& kPos = m_spCamera->GetTranslation();

		m_spCamera->SetTranslation(kPos + kDown*m_kfMoveSpeed);
	}
}
//----------------------------------------------------
/**
*  Moves camera right
* 
**/
void CameraMover::MoveCameraRight()
{
	m_spCamera = m_pRenderer->GetCamera();

	if (m_spCamera)
	{
		const mth::Vector3& kRight = m_spCamera->GetGlobalRotation().GetColumn(0);
		const mth::Vector3& kPos = m_spCamera->GetTranslation();

		m_spCamera->SetTranslation(kPos + kRight*m_kfMoveSpeed);
	}
}
//----------------------------------------------------
/**
*  Moves camera left
* 
**/
void CameraMover::MoveCameraLeft()
{
	m_spCamera = m_pRenderer->GetCamera();

	if (m_spCamera)
	{
		const mth::Vector3& kLeft = -m_spCamera->GetGlobalRotation().GetColumn(0);
		const mth::Vector3& kPos = m_spCamera->GetTranslation();

		m_spCamera->SetTranslation(kPos + kLeft*m_kfMoveSpeed);
	}
}
//----------------------------------------------------
/**
*  Moves camera forward
* 
**/
void CameraMover::MoveCameraForward()
{
	m_spCamera = m_pRenderer->GetCamera();

	if (m_spCamera)
	{
		const mth::Vector3& kFor = -m_spCamera->GetGlobalRotation().GetColumn(2);
		const mth::Vector3& kPos = m_spCamera->GetTranslation();

		m_spCamera->SetTranslation(kPos + kFor*m_kfMoveSpeed);
	}
}
//----------------------------------------------------
/**
*  Moves camera back
* 
**/
void CameraMover::MoveCameraBack()
{
	m_spCamera = m_pRenderer->GetCamera();

	if (m_spCamera)
	{
		const mth::Vector3& kBack = m_spCamera->GetGlobalRotation().GetColumn(2);
		const mth::Vector3& kPos = m_spCamera->GetTranslation();

		m_spCamera->SetTranslation(kPos + kBack*m_kfMoveSpeed);
	}
}
//----------------------------------------------------
/**
*  Creates a move up event
* 
**/
void CameraMover::CreateMoveUpEvent()
{
	if (m_pEventMgr)
		m_pEventMgr->AddEvent(Event(Event::EVENT_MOVE_CAMERA_UP));
}
//----------------------------------------------------
/**
*  Creates a move down event
* 
**/
void CameraMover::CreateMoveDownEvent()
{
	if (m_pEventMgr)
		m_pEventMgr->AddEvent(Event(Event::EVENT_MOVE_CAMERA_DOWN));
}
//----------------------------------------------------
/**
*  Creates a move right event
* 
**/
void CameraMover::CreateMoveRightEvent()
{
	if (m_pEventMgr)
		m_pEventMgr->AddEvent(Event(Event::EVENT_MOVE_CAMERA_RIGHT));
}
//----------------------------------------------------
/**
*  Creates a move left event
* 
**/
void CameraMover::CreateMoveLeftEvent()
{
	if (m_pEventMgr)
		m_pEventMgr->AddEvent(Event(Event::EVENT_MOVE_CAMERA_LEFT));
}
//----------------------------------------------------
/**
*  Creates a move forward event
* 
**/
void CameraMover::CreateMoveForwardEvent()
{
	if (m_pEventMgr)
		m_pEventMgr->AddEvent(Event(Event::EVENT_MOVE_CAMERA_FORWARD));
}

//----------------------------------------------------
/**
*  Creates a move back event
* 
**/
void CameraMover::CreateMoveBackEvent()
{
	if (m_pEventMgr)
		m_pEventMgr->AddEvent(Event(Event::EVENT_MOVE_CAMERA_BACK));
}